/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Raytracing.BRDF;
import Raytracing.Constants;
import processing.core.PVector;
import Raytracing.Constants.*;
import Raytracing.Ray;
import Raytracing.Sampling;

/**
 *
 * @author Matt
 */
public class AshShirBRDF implements BRDF {
    private float ps = .5f;
    private float nu = 50;
    private float nv = 50;

    private PVector albedo = new PVector(.9f,.9f,.9f);

       
    public AshShirBRDF(PVector albedo){

        this.albedo = albedo;
    }
    
     
    public PVector getReflectance(PVector incoming, PVector outgoing, PVector normal, float tu, float tv, PVector u, PVector v) {

        //An Anisotropic Phong BRDF Model Michael Ashikhmin Peter Shirley
        
        PVector ks = PVector.mult(albedo,ps);
        
        //scalar + anisotropic terms
        float an = (float)Math.sqrt((nu + 1)*(nv + 1))/(8*Constants.PI);
        
        //generate the half vector
        PVector h = PVector.add(incoming,outgoing);
        h.normalize();        
        
        //Schlick approximation
        float cosa = 1.f - incoming.dot(h);
        cosa = cosa*cosa*cosa*cosa*cosa;
        PVector F = ks.get();
        
        F.x = 1.f-F.x;
        F.y = 1.f-F.y;
        F.z = 1.f-F.z;
        
        F.mult(cosa);
        
        F.add(ks);
        
        
        //num
        float nh = h.dot(normal);
        
        float hu = h.dot(u);
        hu= hu*hu*nu;
                
        float hv = h.dot(v);
        hv = hv*hv*nv;
        
        float expden = 1 - (nh*nh);
        
        nh = (float)Math.pow(nh,((hu + hv)/expden));
        
        //den
        float hk = h.dot(incoming);
        
        float ek = h.dot(outgoing);
        
        float max = Constants.max(hk,ek);
        
        max *= hk;
        
        
        F.mult(an*nh);
        F.div(max*ps);
        
        return F;

  
     }
    public float sampleReflectance(PVector outgoing, Ray sample,
            PVector normal, PVector BRDF,
            float tu, float tv, PVector u, PVector v,
            float u1, float u2) {
        
        Sampling.cosineSampleHemisphere(sample.direction, u1, u2);
        
        BRDF = getReflectance(sample.direction, outgoing, normal, tu, tv, u, v);
        
                sample.bounceType = Ray.DIFFUSE;
        
        return 1.f / Constants.PI;
    }
    
    
}
